

package com.kimo.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.kimo.shop.bean.app.dto.MyOrderDto;
import com.kimo.shop.bean.app.dto.OrderCountData;
import com.kimo.shop.bean.app.dto.ShopCartOrderMergerDto;
import com.kimo.shop.bean.enums.*;
import com.kimo.shop.bean.event.CancelOrderEvent;
import com.kimo.shop.bean.event.ReceiptOrderEvent;
import com.kimo.shop.bean.event.SubmitOrderEvent;
import com.kimo.shop.bean.event.SubmitScoreOrderEvent;
import com.kimo.shop.bean.model.*;
import com.kimo.shop.bean.param.*;
import com.kimo.shop.bean.vo.UnDeliveryOrderExcelVO;
import com.kimo.shop.common.config.Constant;
import com.kimo.shop.common.enums.PayType;
import com.kimo.shop.common.exception.KimoShopBindException;
import com.kimo.shop.common.i18n.I18nMessage;
import com.kimo.shop.common.util.*;
import com.kimo.shop.dao.*;
import com.kimo.shop.service.*;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

/**
 * @author kimo-taozhouchuan on 2018/09/15.
 */
@Service
@AllArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final OrderMapper orderMapper;
    private final StationService stationService;
    private final DeliveryService deliveryService;
    private final NotifyTemplateService notifyTemplateService;
    private final SkuMapper skuMapper;

    private final OrderItemService orderItemService;

    private final OrderSettlementService orderSettlementService;
    private final PayManagerService payManagerService;

    private final ProductMapper productMapper;

    private final ApplicationEventPublisher eventPublisher;
    private final OrderLangMapper orderlangMapper;

    private final OrderRefundMapper orderRefundMapper;

    private final UserMapper userMapper;
    private final FlowPageAnalyseUserMapper flowPageAnalyseUserMapper;
    private final UserExtensionMapper userExtensionMapper;
    private final OrderRetailProdLogService orderRetailProdLogService;
    private final OrderInvoiceService orderInvoiceService;


    @Override
    public Order getOrderByOrderNumber(String orderNumber) {
        return orderMapper.getOrderByOrderNumber(orderNumber);
    }


    @Override
    public void getOrderItenRefundStatus(Order order) {
        if (Objects.nonNull(order.getRefundStatus()) && order.getRefundStatus() != 4){
            List<OrderRefund> processingOrderRefundByOrderId = orderRefundMapper.getProcessingOrderRefundByOrderId(order.getOrderId());
            for (OrderRefund orderRefund:processingOrderRefundByOrderId){
                //整单退款
                if (orderRefund.getRefundType() == 1){
                    for(OrderItem orderItem:order.getOrderItems()){
                        orderItem.setReturnMoneySts(orderRefund.getReturnMoneySts());
                    }
                    break;
                }
                // 单项退款，每个单号都不一样
                for(OrderItem orderItem:order.getOrderItems()){
                    if (Objects.equals(orderItem.getOrderItemId(), orderRefund.getOrderItemId())) {
                        orderItem.setReturnMoneySts(orderRefund.getReturnMoneySts());
                    }
                }
            }
        }
    }

    @Override
    public Order getOrderByOrderNumberAndUserId(String orderNumber, String userId, boolean valid) {
        Order order = orderMapper.getOrderByOrderNumberAndUserId(orderNumber, userId);
        if (valid && order == null) {
            // 订单不存在
            throw new KimoShopBindException("kimo.order.no.exist");
        }
        return order;
    }

    @Override
    public Order getOrderDetailByOrderNumberAndShopId(String orderNumber, Long shopId, Integer dbLang) {
        return orderMapper.getOrderDetailByOrderNumberAndShopId(orderNumber,shopId,dbLang);
    }

    @Override
    public OrderPayParam getPayUserCountByshopId(Long shopId, Date startTime, Date endTime) {
        OrderPayParam nowOrderPay = orderMapper.getOrderCountByShopId(shopId, startTime, endTime);
        StatisticsRefundParam refundParam = orderRefundMapper.getRefundByShopId(shopId, startTime, endTime);
        Double onePrice = (nowOrderPay.getPayUserCount() == 0) ? 0 : (Arith.div(nowOrderPay.getPayActualTotal(), nowOrderPay.getPayUserCount(),2));
        if (nowOrderPay.getPayActualTotal() == null) {
            nowOrderPay.setPayActualTotal(0.00);
        }
        nowOrderPay.setOnePrice(onePrice)
                .setRefund(refundParam.getPayActualTotal());
        return nowOrderPay;
    }

    @Override
    public OrderPayParam getActualTotalByHour(Long shopId, Date startTime, Date endTime) {
        List<OrderPayParam> actualTotalByHour = orderMapper.getActualTotalByHour(shopId, startTime, endTime);
        Map<Integer, Double> payMap = new HashMap<>(30);
        for (OrderPayParam orderPay : actualTotalByHour) {
            payMap.put(Integer.parseInt(orderPay.getDates()), orderPay.getPayActualTotal());
        }
        List<OrderPayParam> yesterdayTotalByHour = orderMapper.getActualTotalByHour(shopId, DateUtil.beginOfDay(DateUtil.yesterday()),
                DateUtil.endOfDay(DateUtil.yesterday()));
        Map<Integer, Double> yesterdayPayMap = new HashMap<>(30);
        for (OrderPayParam orderPay : yesterdayTotalByHour) {
            yesterdayPayMap.put(Integer.parseInt(orderPay.getDates()), orderPay.getPayActualTotal());
        }
        double sum = 0.00;
        double yesterdaySum = 0.00;
        List<Double> payYesterdayActualTotal = new ArrayList<>();
        List<Double> nowActualTotal = new ArrayList<>();
        OrderPayParam param = new OrderPayParam();
        for (int i = 0; i < 24; i++) {
            if (payMap.get(i) != null) {
                sum = Arith.add(sum,payMap.get(i));
            }
            if (yesterdayPayMap.get(i) != null) {
                yesterdaySum = Arith.add(yesterdaySum,yesterdayPayMap.get(i));
            }
            payYesterdayActualTotal.add(Arith.round(yesterdaySum, 2));
            nowActualTotal.add(Arith.round(sum, 2));
        }
        param.setPayYesterdayActualTotal(payYesterdayActualTotal);
        param.setNowActualTotal(nowActualTotal);
        return param;
    }

    @Override
    public IPage<MyOrderDto> orderListByStatus(PageParam<MyOrderDto> page, Integer status, Long stationId) {
        page.setRecords(orderMapper.orderListByStatusAndStationId(new PageAdapter(page), status, stationId));
        List<MyOrderDto> orderDtoList = page.getRecords();
        for (MyOrderDto myOrderDto : orderDtoList) {
            if(StrUtil.isBlank(myOrderDto.getShopName())){
                myOrderDto.setShopName(Constant.PLATFORM_SHOP_NAME);
            }
        }
        page.setTotal(orderMapper.countMyOrderByUserIdAndStatus(null, status,null,stationId));
        return page;
    }

    @Override
    public List<OrderPayParam> getActualTotalByDay(Long shopId, Date startTime, Date endTime) {
        List<OrderPayParam> actualTotal = orderMapper.getPayOrderByTime(shopId, startTime, endTime);
        List<OrderPayParam> actualTotalByDay = new ArrayList<>();
        //获取本月起始时间
        DateTime dateTime = DateUtil.beginOfMonth(DateUtil.date());
        Double sum = 0.00;
        for (OrderPayParam orderPayParam : actualTotal) {
            DateTime time = DateTime.of(orderPayParam.getDates(), "yyyy-MM-dd");
            if(DateUtil.compare(time,dateTime) > 0){
                sum = Arith.add(sum,orderPayParam.getPayActualTotal());
                orderPayParam.setOnePrice(Arith.round(sum,2));
            }
            actualTotalByDay.add(orderPayParam);
        }
        return actualTotalByDay;
    }

    @Override
    public Order getOrderByOrderNumberAndShopId(String orderNumber, Long shopId, boolean valid) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderNumber).eq(Order::getShopId, shopId));
        if (valid && order == null) {
            // 订单不存在
            throw new KimoShopBindException("kimo.order.no.exist");
        }
        return order;
    }

    @Override
    @CachePut(cacheNames = "ConfirmOrderCache", key = "#userId")
    public ShopCartOrderMergerDto putConfirmOrderCache(String userId, ShopCartOrderMergerDto shopCartOrderMergerDto) {
        return shopCartOrderMergerDto;
    }

    @Override
    @Cacheable(cacheNames = "ConfirmOrderCache", key = "#userId")
    public ShopCartOrderMergerDto getConfirmOrderCache(String userId) {
        return null;
    }

    @Override
    @CacheEvict(cacheNames = "ConfirmOrderCache", key = "#userId")
    public void removeConfirmOrderCache(String userId) {
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Order> submit(String userId, ShopCartOrderMergerDto mergerOrder) {
        List<Order> orderList = new ArrayList<>();
        // 提交订单
        eventPublisher.publishEvent(new SubmitOrderEvent(mergerOrder, orderList));

        // 插入订单
        orderList.forEach(order -> orderMapper.insert(order));
        // 保存订单语言表
        orderlangMapper.insertBatchOrderLang(orderList);
        List<OrderItem> orderItems = orderList.stream().flatMap(order -> order.getOrderItems().stream()).collect(Collectors.toList());
        // 插入订单项，返回主键
        orderItemService.insertBatchOrderItem(orderItems);
        //计算积分情况
        if (mergerOrder.getIsScorePay() != null && mergerOrder.getIsScorePay() == 1) {
            eventPublisher.publishEvent(new SubmitScoreOrderEvent(mergerOrder, orderList));
        }
        return orderList;
    }


    @Override
    public Order getOrderAndOrderItemByOrderNumber(String orderNumber) {
        return orderMapper.getOrderAndOrderItemByOrderNumber(orderNumber);
    }

    @Override
    public Boolean orderStationByOrderNumber(List<String> orderNumberList, String userId, Long stationId) {
        if(CollUtil.isEmpty(orderNumberList)){
            // 请选择最少一个需要自提的订单
            throw new KimoShopBindException("kimo.order.need.station");
        }
        Order orderParam = new Order();
        List<Order> orderList = orderMapper.getStationOrderByOrderNumbers(orderNumberList,userId,stationId);
        for (Order order:orderList){
            if(Objects.isNull(order)){
                // 订单不存在
                throw new KimoShopBindException("kimo.order.no.exist");
            }
            if (Objects.nonNull(order.getRefundStatus()) && (Objects.equals(order.getRefundStatus(), RefundStatusEnum.APPLY.value())
                    || Objects.equals(order.getRefundStatus(), RefundStatusEnum.SUCCEED.value()))) {
                // 订单退款中，无法自提
                throw new KimoShopBindException(I18nMessage.getMessage("kimo.order") + order.getOrderNumber() + I18nMessage.getMessage("kimo.order.station.check"));
            }
            if (!Objects.equals(order.getStatus(),OrderStatus.PADYED.value())){
                // 订单已提货
                throw new KimoShopBindException(I18nMessage.getMessage("kimo.order") + order.getOrderNumber() + I18nMessage.getMessage("kimo.order.station.finish"));
            }
            orderParam = order;
            order.setStatus(OrderStatus.CONSIGNMENT.value());
            order.setDvyTime(new Date());

        }
        // 消息推送-自提点核销通知
        if (orderList.size() > 1){
            orderParam.setOrderNumber(orderParam.getOrderNumber() + "......");
        }
        if(Objects.isNull(stationId)){
            stationId = orderParam.getDvyId();
        }
        Station station = stationService.getById(stationId);
        notifyTemplateService.writeOffOrder(station.getStationName(),orderParam);
        updateBatchById(orderList);
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delivery(Order order) {
        orderMapper.updateById(order);
        // 消息推送-发货提醒
        Delivery delivery = deliveryService.getById(order.getDvyId());
        String dvyName = "";
        if(delivery.getDvyName() != null){
            dvyName = delivery.getDvyName();
        }
        notifyTemplateService.sendNotifyOfDelivery(order,dvyName, SendType.DELIVERY);

    }

    @Override
    public List<Order> listUnRefundOrderAndOrderItems(Integer orderStatus, DateTime lessThanUpdateTime) {
        return orderMapper.listUnRefundOrderAndOrderItems(orderStatus, lessThanUpdateTime);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrders(List<Order> orders) {
        if (CollectionUtil.isEmpty(orders)) {
            return;
        }
        orderMapper.cancelOrders(orders);
        List<OrderItem> allOrderItems = new ArrayList<>();
        List<OrderRetailProdLog> list = new ArrayList<>();
        List<Long> retailProdIds = new ArrayList<>();
        List<Long> retailSkuIds = new ArrayList<>();
        for (Order order : orders) {
            List<OrderItem> orderItems = order.getOrderItems();
            allOrderItems.addAll(orderItems);
            eventPublisher.publishEvent(new CancelOrderEvent(order));
            // 还原单品商品的库存,如果是组合商品
            List<OrderRetailProdLog> orderRetailProdLogs =  orderRetailProdLogService.returnStocksByOrderNumber(order.getOrderNumber());
            if (CollUtil.isNotEmpty(orderRetailProdLogs)) {
                list.addAll(orderRetailProdLogs);
            }
        }
        // 如果是秒杀订单也不必还原库存
        if (CollectionUtil.isEmpty(allOrderItems) || OrderType.SECKILL.value().equals(orders.get(0).getOrderType())) {
            return;
        }
        if (CollUtil.isNotEmpty(list)) {
            retailProdIds = list.stream().map(OrderRetailProdLog::getProdId).collect(Collectors.toList());
            retailSkuIds = list.stream().map(OrderRetailProdLog::getSkuId).collect(Collectors.toList());
        }
        // 过滤掉已经还原了单品的库存的商品
        Map<Long, Integer> prodCollect = new HashMap<>(16);
        List<Long> finalRetailProdIds = retailProdIds;
        allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getProdId)).forEach((prodId, orderItems) -> {
            int prodTotalNum = orderItems.stream().mapToInt(OrderItem::getProdCount).sum();
            if (!finalRetailProdIds.contains(prodId)) {
                prodCollect.put(prodId, prodTotalNum);
            }
        });
        if (!prodCollect.isEmpty()) {
            productMapper.returnStock(prodCollect);
        }
        List<Long> finalRetailSkuIds = retailSkuIds;
        Map<Long, Integer> skuCollect = new HashMap<>(16);
        allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getSkuId)).forEach((skuId, orderItems) -> {
            int prodTotalNum = orderItems.stream().mapToInt(OrderItem::getProdCount).sum();
            if (!finalRetailSkuIds.contains(skuId)) {
                skuCollect.put(skuId, prodTotalNum);
            }
        });
        if (!skuCollect.isEmpty()) {
            skuMapper.returnStock(skuCollect);
        }
        // 查询出微信支付并且为二维码支付的，失效掉对应支付二维码
        List<String> orderNumbers = new ArrayList<>();
        for (Order order : orders) {
            if(Objects.isNull(order.getPayType())){
                continue;
            }
            // 如果是支付宝支付，或者微信 二维码支付直接使二维码失效
            if (Objects.equals(order.getPayType(), PayType.ALIPAY.value()) ||
                    Objects.equals(order.getPayType(), PayType.WECHATPAY_SWEEP_CODE.value())){
                orderNumbers.add(order.getOrderNumber());
            }
        }
        if(CollectionUtils.isEmpty(orderNumbers)){
            return;
        }

        // 如果有重复的payNo，不用失效掉二维码。
        List<OrderSettlement> filterOrderSettlement = orderSettlementService.listByOrderNumbers(orderNumbers);
        try {
            payManagerService.cancelOrderQrCode(filterOrderSettlement);
        }catch (Exception e){
            log.error("失效支付二维码失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiptOrder(List<Order> orders) {
        orderMapper.receiptOrder(orders);
        for (Order order : orders) {
            eventPublisher.publishEvent(new ReceiptOrderEvent(order));
            // 消息推送-用户已确认收货
            notifyTemplateService.sendNotifyByUserRefundDelivery(order, SendType.RECEIPT_ORDER);
        }

    }

    @Override
    public List<Order> listOrdersDetialByOrder(Order order, Date startTime, Date endTime) {
        return orderMapper.listOrdersDetialByOrder(order, startTime, endTime);
    }

    @Override
    public IPage<Order> pageOrdersDetialByOrderParam(Page<Order> page, OrderParam orderParam) {
        List<Order> orders = orderMapper.listOrdersDetialByOrderParam(new PageAdapter(page), orderParam);
        for (Order order : orders) {
            if(StrUtil.isNotBlank(order.getReceiverName()) && CharUtil.length(order.getReceiverName()) > 8){
                order.setReceiverName(order.getReceiverName().substring(0, Math.min(8, order.getReceiverName().length() - 1)) + "...");
            }
        }
        page.setRecords(orders);
        page.setTotal(orderMapper.countOrderDetial(orderParam));
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrders(List<Order> orders) {
        orderMapper.deleteOrders(orders);
    }

    @Override
    public OrderCountData getOrderCount(String userId) {
        return orderMapper.getOrderCount(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeAmount(Order order) {
        Order orderDb = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderId, order.getOrderId())
                .eq(Order::getOrderNumber, order.getOrderNumber())
        );
        if (!Objects.equals(orderDb.getStatus(), OrderStatus.UNPAY.value())){
            // 订单状态异常，无法更改订单金额
            throw new KimoShopBindException("kimo.order.unrecognized.update");
        }
        Integer changeAmountVersion = orderDb.getChangeAmountVersion() + 1;
        //减少金额
        double amount = 0.00;
        //平台优惠金额
        Map<Long, OrderItem> collect = order.getOrderItems().stream().collect(Collectors.toMap(OrderItem::getOrderItemId, orderItem -> orderItem));
        List<OrderItem> orderItemList = orderItemService.list(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()));
        for (OrderItem orderItemDb:orderItemList){
            OrderItem orderItem = collect.get(orderItemDb.getOrderItemId());
            if (orderItem.getChageAmount() >= orderItemDb.getActualTotal() || orderItem.getChageAmount() < 0){
                // 订单金额必须大于0，或者数据发生变化(请刷新后重试）
                throw new KimoShopBindException("kimo.order.amount.check");
            }
            if (Objects.isNull(orderItem.getChageAmount()) || Objects.equals(orderItem.getChageAmount(),0.00)){
                continue;
            }
            //实际金额 = 原实际金额 - 减少金额
            orderItemDb.setActualTotal(Arith.sub(orderItemDb.getActualTotal(),orderItem.getChageAmount()));
            //总优惠金额 = 减少金额 + 原总优惠金额
            orderItemDb.setShareReduce(Arith.add(orderItem.getChageAmount(),orderItemDb.getShareReduce()));
            orderItemDb.setChangeAmountVersion(changeAmountVersion);
            amount = Arith.add(amount,orderItem.getChageAmount());
        }
        orderItemService.updateBatchById(orderItemList);
        OrderSettlement orderSettlement = orderSettlementService.getOne(new LambdaQueryWrapper<OrderSettlement>().eq(OrderSettlement::getOrderNumber, order.getOrderNumber()));
        //修改订单信息
        orderDb.setActualTotal(Arith.sub(orderDb.getActualTotal(),amount));
        orderDb.setReduceAmount(Arith.add(amount,orderDb.getReduceAmount()));
        //初始化
        amount = 0.00;
        // 计算运费变化金额
        if(!Objects.equals(orderDb.getFreightAmount(),order.getFreightAmount())){
            amount = Arith.add(amount,Arith.sub(order.getFreightAmount(),orderDb.getFreightAmount()));
        }
        orderDb.setActualTotal(Arith.add(orderDb.getActualTotal(),amount));
        orderSettlement.setPayAmount(orderDb.getActualTotal());
        orderSettlement.setChangeAmountVersion(changeAmountVersion);
        orderSettlementService.updateById(orderSettlement);
        //修改运费信息
        orderDb.setFreightAmount(order.getFreightAmount());
        orderDb.setChangeAmountVersion(changeAmountVersion);
        orderMapper.updateById(orderDb);
    }

    @Override
    public List<Order> getOrderPayInfoByOrderNumber(List<String> orderNumberList) {
        return orderMapper.getOrderPayInfoByOrderNumber(orderNumberList);
    }

    @Override
    public Map<Long, Integer> getOrderItemMap(Long orderId) {
        List<OrderRefund> orderRefunds = orderRefundMapper.selectList(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderId)
                .lt(OrderRefund::getReturnMoneySts,6)
                .gt(OrderRefund::getReturnMoneySts,0)
        );
        Map<Long, Integer> map = Maps.newHashMap();

        for (OrderRefund orderRefund:orderRefunds){
            if (orderRefund.getRefundType() == 1){
                map.put(0L,orderRefund.getReturnMoneySts());
                return map;
            }
            map.put(orderRefund.getOrderItemId(),orderRefund.getReturnMoneySts());
        }
        return map;
    }

    @Override
    public List<Order> getOrderAndOrderItemByOrderNumberList(Set<String> orderNumberList) {
        return orderMapper.getOrderAndOrderItemByOrderNumberList(orderNumberList);
    }
    @Override
    public List<CustomerRFMRespTableParam> countPayNumRFM2(CustomerRFMReqParam param) {

        Date recentTime = param.getRecentTime();
        Date mouth = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -30));
        Date threeMouth = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -90));
        Date halfYear = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -180));
        Date year = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -365));
        List<CustomerRFMRespTableParam> dateList = orderMapper.getUserOrderCrateTime(param.getType(),mouth,threeMouth,halfYear,year);
        return dateList;
    }

    @Override
    public UserManagerParam getConsumeData(UserManagerParam param) {
        String userId = param.getUserId();
        // 最近消费时间, 下单支付的时间(积分支付/余额支付), 充值时间， 比较获取最新时间
        Date date = orderMapper.getLastConsumeDateByUserId(param.getUserId());
        param.setReConsTime(date);
        // 消费金额, 累计消费了多少金额：除了积分支付的订单累计金额
        Double amount = orderMapper.countConsumeAmount(userId, 1);
        param.setConsAmount(Objects.nonNull(amount)?amount:0.0);
        // 实付金额, 累计支付的金额: 除了余额支付/积分支付的订单累计金额 + 余额充值金额
        param.setActualAmount(orderMapper.countConsumeAmount(userId, 0));
        // 消费次数, 累计消费的次数（积分下单不包含），下单的次数
        param.setConsTimes(orderMapper.countPayNumByUserId(userId));
        // 平均折扣, 消费下单的优惠总金额/消费次数
        // 优惠总金额
        Double reduceAmount = orderMapper.countReduceAmountByUserId(userId);
        param.setAverDiscount(divAverage(reduceAmount,param.getConsTimes(),2));
        return param;
    }

    @Override
    public IPage<Order> pageByUserId(PageParam<Order> page, String userId) {
        return orderMapper.getPageByUserId(page,userId);
    }

    @Override
    public Integer countByOrderNumber(String orderNumber) {
        return orderMapper.countByOrderNumber(orderNumber);
    }

    @Override
    public CustomerRespParam countPayNum(CustomerReqParam param) {
        CustomerRespParam res = new CustomerRespParam();
        param.setDateTime(null);
        res.setPayNum(orderMapper.countPayCustomerNum(param));
        getPreDateByRangeTime(param);
        res.setPrePayNum(orderMapper.countPayCustomerNum(param));
        res.setPayNumRate(divAverage(res.getPayNum() - res.getPrePayNum(), res.getPayNum(), 4));
        return res;
    }

    /**
     * 开始时间和结束时间的时间差n天
     * 结束时间是开始时间，开始时间的前n天作为开始时间
     * @param param 时间参数
     */
    private void getPreDateByRangeTime(CustomerReqParam param) {
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        long days = DateUtil.between(startTime, endTime, DateUnit.DAY);
        DateTime dateTime = DateUtil.offsetDay(startTime, -(int) days);
        param.setStartTime(DateUtil.beginOfDay(dateTime));
        param.setEndTime(DateUtil.endOfDay(startTime));
    }

    @Override
    public List<CustomerPayParam> countCustomerParam(CustomerReqParam param) {
        List<DateParam> everyDays = DateUtils.findEveryDays(param.getStartTime(), param.getEndTime());
        List<CustomerPayParam> res = new ArrayList<>();
        for (DateParam everyDay : everyDays) {
            CustomerPayParam respParam = new CustomerPayParam();
            param.setStartTime(everyDay.getStartTime());
            param.setEndTime(everyDay.getEndTime());
            param.setDateTime(null);
            respParam.setCurrentDay(DateUtils.dateToStrYMD(everyDay.getStartTime()));
            // 访客数
            respParam.setVisitor(flowPageAnalyseUserMapper.countAllVisitor(null,param.getStartTime(),param.getEndTime()));
            // 累积粉丝数，不统计
            respParam.setFashNum(userMapper.countUserByParam(param));
            // 累积会员数 , 页面重复统计，这里不统计
//            respParam.setMember(userMapper.countMemberByParam(param));
            // 成交客户数
            respParam.setPayNum(orderMapper.countPayCustomerNum(param));
            res.add(respParam);
        }
        return res;
    }

    @Override
    public Integer countMemberPayNum(CustomerReqParam param) {
        return orderMapper.countMemberPayNum(param);
    }

    @Override
    public CustomerDealRespParam getCustomerDeal(CustomerReqParam param) {
        CustomerDealRespParam res = new CustomerDealRespParam();
        CustomerDealParam allDeal = new CustomerDealParam();
        CustomerDealParam newDeal = new CustomerDealParam();
        CustomerDealParam oldDeal = new CustomerDealParam();
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        param.setDateTime(null);
        // 客户数
        allDeal.setCustomerNum(orderMapper.countMemberPayNum(param));
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        newDeal.setCustomerNum(orderMapper.countNewMemberPayNum(beforeYear, startTime, endTime));
        oldDeal.setCustomerNum(orderMapper.countOldMemberPayNum(beforeYear, startTime, endTime));
        // 付款金额
        allDeal.setPayAmount(getDouble(orderMapper.countMemberPayAmount(param)));
        newDeal.setPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime, endTime)));
        oldDeal.setPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime, endTime)));
        // 客户数占比
        param.setStartTime(null);
        param.setEndTime(null);
        Integer allUsers = userMapper.countUserByParam(param);
        allDeal.setCustomerRate(divAverage(allDeal.getCustomerNum(), allUsers, 4));
        newDeal.setCustomerRate(divAverage(newDeal.getCustomerNum(), allDeal.getCustomerNum(), 4));
        oldDeal.setCustomerRate(divAverage(oldDeal.getCustomerNum(), allDeal.getCustomerNum(), 4));
        // 客单价
        allDeal.setCustomerSinglePrice(divAverage(allDeal.getPayAmount(), allDeal.getCustomerNum(), 4));
        newDeal.setCustomerSinglePrice(divAverage(newDeal.getPayAmount(), newDeal.getCustomerNum(), 4));
        oldDeal.setCustomerSinglePrice(divAverage(oldDeal.getPayAmount(), oldDeal.getCustomerNum(), 4));
        // 访问-付款转化率
        // 两年的总访客数
        Integer totalVisitor = flowPageAnalyseUserMapper.countVisitorNumByDate(beforeYear,endTime);
        // 支付访客数
        Integer payVisitor = flowPageAnalyseUserMapper.countPaidVisitorNumByDate(beforeYear,endTime);
        // 未支付访客数 = 两年的总访客数 - 支付访客数
        allDeal.setTransRate(divAverage(allDeal.getCustomerNum(),totalVisitor,4));
        newDeal.setTransRate(divAverage(newDeal.getCustomerNum(),totalVisitor-payVisitor,4));
        oldDeal.setTransRate(divAverage(oldDeal.getCustomerNum(),payVisitor,4));
        res.setAllDeal(allDeal);
        res.setNewDeal(newDeal);
        res.setOldDeal(oldDeal);
        List<CustomerDealTrendParam> listDeal = new ArrayList<>();
        List<DateParam> everyDays = DateUtils.findEveryDays(startTime, endTime);
        for (DateParam everyDay : everyDays) {
            CustomerDealTrendParam trend = new CustomerDealTrendParam();
            Date startTime1 = everyDay.getStartTime();
            Date endTime1 = everyDay.getEndTime();
            trend.setCurrentDay(DateUtils.dateToStrYMD(everyDay.getEndTime()));
            trend.setNewCustomerNum(orderMapper.countNewMemberPayNum(beforeYear, startTime1, endTime1));
            trend.setOldCustomerNum(orderMapper.countOldMemberPayNum(beforeYear, startTime1, endTime1));
            trend.setNewPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime1, endTime1)));
            trend.setOldPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime1, endTime1)));
            trend.setNewCustomerSinglePrice(divAverage(trend.getNewPayAmount(), trend.getNewCustomerNum(), 4));
            trend.setOldCustomerSinglePrice(divAverage(trend.getOldPayAmount(), trend.getOldCustomerNum(), 4));
            trend.setNewTransRate(divAverage(trend.getNewCustomerNum(),totalVisitor-payVisitor,4));
            trend.setOldTransRate(divAverage(trend.getOldCustomerNum(),payVisitor,4));
            listDeal.add(trend);
        }
        res.setListDeal(listDeal);
        return res;
    }

    @Override
    public List<CustomerRFMRespParam> countPayNumRFM(CustomerRFMReqParam param) {
        List<CustomerRFMRespParam> list = new ArrayList<>();
        Integer type = param.getType();
        Date recentTime = param.getRecentTime();
        // 1 2 3 4 f=5 表示f>=5
        Integer f = 1;
        // R<=30
        Date startTime = new Date();
        Date endTime = recentTime;
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param1 = new CustomerRFMRespParam();
            param1.setRecency(1);
            param1.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -30));
            endTime = recentTime;
            param1.setPayBuyers(orderMapper.countPayNumRFM(1, i, startTime, endTime));
            param1.setPayAmount(getDouble(orderMapper.sumPayAmountRFM(1, i, startTime, endTime)));
            list.add(param1);
        }
        // 30<R<=90
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param2 = new CustomerRFMRespParam();
            param2.setRecency(2);
            param2.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -90));
            endTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -30));
            param2.setPayBuyers(orderMapper.countPayNumRFM(1, i, startTime, endTime));
            param2.setPayAmount(getDouble(orderMapper.sumPayAmountRFM(1, i, startTime, endTime)));
            list.add(param2);
        }
        // 90<R<=180
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param3 = new CustomerRFMRespParam();
            param3.setRecency(3);
            param3.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -180));
            endTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -90));
            param3.setPayBuyers(orderMapper.countPayNumRFM(1, i, startTime, endTime));
            param3.setPayAmount(getDouble(orderMapper.sumPayAmountRFM(1, i, startTime, endTime)));
            list.add(param3);
        }
        // 180<R<=365
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param4 = new CustomerRFMRespParam();
            param4.setRecency(4);
            param4.setFrequency(i);
            startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -365));
            endTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -180));
            param4.setPayBuyers(orderMapper.countPayNumRFM(1, i, startTime, endTime));
            param4.setPayAmount(getDouble(orderMapper.sumPayAmountRFM(1, i, startTime, endTime)));
            list.add(param4);
        }
        // R > 365
        for (int i = 1; i < 6; i++) {
            CustomerRFMRespParam param4 = new CustomerRFMRespParam();
            param4.setRecency(5);
            param4.setFrequency(i);
            Integer payBuyers = 0;
            Double amount = 0.0;
            if (Objects.equals(0, type)) {
                startTime = DateUtils.dateToFast(DateUtils.getBeforeDay(recentTime, -365));
                payBuyers = orderMapper.countPayNumRFM(0, i, startTime, null);
                amount = getDouble(orderMapper.sumPayAmountRFM(0, i, startTime, null));
            }
            param4.setPayBuyers(payBuyers);
            param4.setPayAmount(amount);
            list.add(param4);
        }
        return list;
    }

    @Override
    public CustomerConsumeRespParam getConsumePower(CustomerConsumeReqParam param) {
        CustomerConsumeRespParam respParam = new CustomerConsumeRespParam();
        respParam.setStart(0.0D);
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        Integer type = param.getType();
        // 0全部成交客户 1新成交客户 2老成交客户
        if (!Objects.equals(2, type)) {
            respParam.setNewPayBuyers(orderMapper.countNewMemberPayNum(beforeYear, startTime, endTime));
            respParam.setNewPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime, endTime)));
            respParam.setNewPayProdCount(getInteger(orderMapper.countNewOrOldPayProdNum(0, beforeYear, startTime, endTime)));
        }
        if (Objects.equals(1, type)) {
            respParam.setEnd(Math.ceil(respParam.getNewPayAmount()));
            return respParam;
        }
        respParam.setOldPayBuyers(orderMapper.countOldMemberPayNum(beforeYear, startTime, endTime));
        respParam.setOldPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime, endTime)));
        respParam.setOldPayProdCount(getInteger(orderMapper.countNewOrOldPayProdNum(1, beforeYear, startTime, endTime)));
        if (Objects.equals(2, type)) {
            respParam.setEnd(Math.ceil(respParam.getOldPayAmount()));
            return respParam;
        }
        respParam.setEnd(Math.ceil(Arith.add(respParam.getNewPayAmount(), respParam.getOldPayAmount())));
        if (respParam.getEnd() <= 50) {
            respParam.setEnd(50.0);
        }
        return respParam;
    }

    @Override
    public CustomerConsumeRespParam getConsumeFrequency(CustomerConsumeReqParam param) {
        CustomerConsumeRespParam respParam = new CustomerConsumeRespParam();
        Integer type = param.getType();
        // 0全部成交客户 1新成交客户 2老成交客户
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        if (!Objects.equals(2, type)) {
            respParam.setNewPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime, endTime)));
            respParam.setNewPayBuyers(orderMapper.countNewMemberPayNum(beforeYear, startTime, endTime));
            respParam.setNewPayProdCount(getInteger(orderMapper.countNewOrOldPayProdNum(0, beforeYear, startTime, endTime)));
        }
        Integer newPayTimes = orderMapper.countNewOrOldPayTimes(0, beforeYear, startTime, endTime);
        if (Objects.equals(1, type)) {
            respParam.setEnd(Double.valueOf(newPayTimes));
            return respParam;
        }
        respParam.setOldPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime, endTime)));
        respParam.setOldPayBuyers(orderMapper.countOldMemberPayNum(beforeYear, startTime, endTime));
        respParam.setOldPayProdCount(getInteger(orderMapper.countNewOrOldPayProdNum(1, beforeYear, startTime, endTime)));
        Integer oldPayTimes = orderMapper.countNewOrOldPayTimes(1, beforeYear, startTime, endTime);
        if (Objects.equals(2, type)) {
            respParam.setEnd(Double.valueOf(oldPayTimes));
            return respParam;
        }
        respParam.setEnd(Double.valueOf(newPayTimes + oldPayTimes));
        return respParam;
    }

    @Override
    public CustomerRepurchaseRespParam getConsumeRepurchaseCount(CustomerConsumeReqParam param) {
        Integer type = param.getType();
        // 0全部成交客户 1新成交客户 2老成交客户
        Date endTime = param.getEndTime();
        Date startTime = param.getStartTime();
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        Integer cycle = -param.getCycle();
        Integer payBuyers = 0;
        Double payAmount = 0.0;
        Integer payProdCount = 0;
        Integer repurchaseCount = 0;
        CustomerRepurchaseRespParam respParam = new CustomerRepurchaseRespParam();
        List<CustomerRepurchaseDetailParam> res = new ArrayList<>();
        CustomerRepurchaseDetailParam deParam = new CustomerRepurchaseDetailParam();
        if (!Objects.equals(2, type)) {
            // 全部/新客户
            List<CustomerOrderParam> orderParams = orderMapper.getNewRepurchaseParam(param.getShopId(), 0, beforeYear, startTime, endTime);
            ArrayList<CustomerOrderParam> collect = orderParams.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(CustomerOrderParam::getUserId))), ArrayList::new));
            payBuyers = payBuyers + collect.size();
            for (CustomerOrderParam orderParam : collect) {
                CustomerRepurchaseDetailParam detailParam = orderMapper.getNewRepurchaseCount(param.getShopId(), 0, cycle, orderParam.getUserId(), orderParam.getPayTime(), beforeYear, startTime, endTime);
                payAmount = Arith.add(payAmount, getDouble(detailParam.getPayAmount()));
                payProdCount = payProdCount + detailParam.getPayProdCount();
                repurchaseCount = repurchaseCount + detailParam.getRepurchaseCount();
            }
        }
        if (!Objects.equals(1, type)) {
            // 全部/老客户
            List<CustomerOrderParam> orderParams = orderMapper.getNewRepurchaseParam(param.getShopId(), 1, beforeYear, startTime, endTime);
            ArrayList<CustomerOrderParam> collect = orderParams.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(CustomerOrderParam::getUserId))), ArrayList::new));
            payBuyers = payBuyers + collect.size();
            for (CustomerOrderParam orderParam : collect) {
                CustomerRepurchaseDetailParam detailParam = orderMapper.getNewRepurchaseCount(param.getShopId(), 1, cycle, orderParam.getUserId(), orderParam.getPayTime(), beforeYear, startTime, endTime);
                payAmount = Arith.add(payAmount, getDouble(detailParam.getPayAmount()));
                payProdCount = payProdCount + detailParam.getPayProdCount();
                repurchaseCount = repurchaseCount + detailParam.getRepurchaseCount();
            }
        }
        deParam.setPayAmount(payAmount);
        deParam.setPayBuyers(payBuyers);
        deParam.setPayProdCount(payProdCount);
        deParam.setRepurchaseCount(repurchaseCount);
        res.add(deParam);
        respParam.setDetail(res);
        return respParam;
    }

    @Override
    public MemberContributeRespParam getMemberContributeValue(MemberReqParam param) {
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        MemberContributeRespParam respParam = new MemberContributeRespParam();
        // 普通会员
        MemberContributeValueParam publicMember = new MemberContributeValueParam();
        // 付费会员
        MemberContributeValueParam paidMember = new MemberContributeValueParam();

        // 普通会员
        param.setDateTime(endTime);
        param.setMemberType(1);
        publicMember.setTotalMember(userExtensionMapper.countMemberByParam(param));
        param.setDateTime(null);
        publicMember.setPayMemberNum(orderMapper.countPaidMemberByParam(param,null));
        // TODO 支付频次暂不统计 时间段内：支付订单数 / 消费人数
        publicMember.setPayOrderNum(orderMapper.countPaidMemberByParam(param,1));
        publicMember.setFrequencyOfConsume(divAverage(publicMember.getPayOrderNum(),publicMember.getPayMemberNum(),2));
        publicMember.setPayAmount(getDouble(orderMapper.countMemberPaidAmount(param)));
        publicMember.setPricePerMember(divAverage(publicMember.getPayAmount(),publicMember.getPayMemberNum(),4));
        // 付费会员
        param.setMemberType(2);
        param.setDateTime(endTime);
        paidMember.setTotalMember(userExtensionMapper.countMemberByParam(param));
        param.setDateTime(null);
        paidMember.setPayMemberNum(orderMapper.countPaidMemberByParam(param,null));
        paidMember.setPayAmount(getDouble(orderMapper.countMemberPaidAmount(param)));
        paidMember.setPayOrderNum(orderMapper.countPaidMemberByParam(param,1));
        paidMember.setFrequencyOfConsume(divAverage(paidMember.getPayOrderNum(),paidMember.getPayMemberNum(),2));
        paidMember.setPricePerMember(divAverage(paidMember.getPayAmount(),paidMember.getPayMemberNum(),4));
        publicMember.setTotalMemberRate(divAverage(publicMember.getTotalMember(),publicMember.getTotalMember()+paidMember.getTotalMember(),4));
        paidMember.setTotalMemberRate(Arith.sub(1,publicMember.getTotalMemberRate()));
        publicMember.setPayMemberNumRate(divAverage(publicMember.getPayMemberNum(),publicMember.getPayMemberNum()+ paidMember.getPayMemberNum(),4));
        paidMember.setPayMemberNumRate(Arith.sub(1,publicMember.getPayMemberNumRate()));
        publicMember.setPayAmountRate(divAverage(publicMember.getPayAmount(),Arith.add(publicMember.getPayAmount(),paidMember.getPayAmount()),4));
        paidMember.setPayAmountRate(Arith.sub(1,publicMember.getPayAmountRate()));

        respParam.setPublicMember(publicMember);
        respParam.setPaidMember(paidMember);
        return respParam;
    }

    @Override
    public MemberDealRespParam getMemberDeal(MemberReqParam param) {
        MemberDealRespParam respParam = new MemberDealRespParam();
        MemberDealParam allMember = new MemberDealParam();
        MemberDealParam newMember = new MemberDealParam();
        MemberDealParam oldMember = new MemberDealParam();
        List<MemberDealTreadParam> trend = new ArrayList<>();
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        param.setDateTime(null);
        // 客户数
        allMember.setPayMemberNum(orderMapper.countMemberPayNum(param));
        Date beforeYear = DateUtils.getBeforeYear(startTime, -2);
        newMember.setPayMemberNum(orderMapper.countNewMemberPayNum(beforeYear, startTime, endTime));
        oldMember.setPayMemberNum(orderMapper.countOldMemberPayNum(beforeYear, startTime, endTime));
        // 成交会员占比
        Integer payMemberNum = allMember.getPayMemberNum();
        allMember.setPayMemberNumRate(1.0);
        newMember.setPayMemberNumRate(divAverage(newMember.getPayMemberNum(),payMemberNum,4));
        oldMember.setPayMemberNumRate(divAverage(oldMember.getPayMemberNum(),payMemberNum,4));
        // 付款金额
        allMember.setPayAmount(getDouble(orderMapper.countMemberPayAmount(param)));
        newMember.setPayAmount(getDouble(orderMapper.countNewMemberPayAmount(beforeYear, startTime, endTime)));
        oldMember.setPayAmount(getDouble(orderMapper.countOldMemberPayAmount(beforeYear, startTime, endTime)));
        // 支付金额占比
        allMember.setPayAmountRate(1.0);
        newMember.setPayAmountRate(divAverage(newMember.getPayAmount(),allMember.getPayAmount(),4));
        oldMember.setPayAmountRate(Arith.sub(allMember.getPayAmountRate(),newMember.getPayAmountRate()));
        // 客单价
        allMember.setPricePerMember(divAverage(allMember.getPayAmount(),allMember.getPayMemberNum(),2));
        newMember.setPricePerMember(divAverage(newMember.getPayAmount(),newMember.getPayMemberNum(),2));
        oldMember.setPricePerMember(divAverage(oldMember.getPayAmount(),oldMember.getPayMemberNum(),2));
        // 支付订单数
        newMember.setPayOrderNum(orderMapper.countNewOrOldMemberPayOrder(0,beforeYear, startTime, endTime));
        oldMember.setPayOrderNum(orderMapper.countNewOrOldMemberPayOrder(1,beforeYear, startTime, endTime));
        allMember.setPayOrderNum(newMember.getPayOrderNum() + oldMember.getPayOrderNum());
        respParam.setAllMember(allMember);
        respParam.setNewMember(newMember);
        respParam.setOldMember(oldMember);
        List<DateParam> everyDays = DateUtils.findEveryDays(startTime, endTime);
        for (DateParam everyDay : everyDays) {
            MemberDealTreadParam res = new MemberDealTreadParam();
            Date dayStartTime = everyDay.getStartTime();
            Date dayEndTime = everyDay.getEndTime();
            res.setCurrentDay(DateUtils.dateToNumber(dayStartTime));
            res.setNewPayMemberNum(orderMapper.countNewMemberEveryDayPayNum(0,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setOldPayMemberNum(orderMapper.countNewMemberEveryDayPayNum(1,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setNewPayOrderNum(orderMapper.countNewOrOldMemberEveryDayPayPayOrder(0,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setOldPayOrderNum(orderMapper.countNewOrOldMemberEveryDayPayPayOrder(1,beforeYear, startTime,dayStartTime, dayEndTime));
            res.setNewPayAmount(getDouble(orderMapper.countNewMemberEveryDayPayAmount(0,beforeYear, startTime,dayStartTime, dayEndTime)));
            res.setOldPayAmount(getDouble(orderMapper.countNewMemberEveryDayPayAmount(1,beforeYear, startTime,dayStartTime, dayEndTime)));
            res.setNewPricePerMember(divAverage(res.getNewPayAmount(),res.getNewPayMemberNum(),2));
            res.setOldpricePerMember(divAverage(res.getOldPayAmount(),res.getOldPayMemberNum(),2));
            trend.add(res);
        }
        respParam.setTrendParam(trend);
        return respParam;
    }

    @Override
    @Cacheable(cacheNames = "tradeRetained", key = "#param.retainType +':'+ #param.dateType" )
    public List<CustomerRetainRespParam> getTradeRetained(CustomerRetainedReqParam param) {
        return orderMapper.getTradeRetained(param);
    }

    @Override
    @CacheEvict(cacheNames = "tradeRetained", key = "#param.retainType +':'+ #param.dateType")
    public void removeCacheTradeRetained(CustomerRetainedReqParam param) {
    }

    @Override
    public UnDeliveryOrderExcelVO getOrderAndOrderItemsByOrderNumberAndShopId(String orderNumber, Long shopId) {
        return orderMapper.getOrderAndOrderItemsByOrderNumberAndShopId(orderNumber,shopId);
    }

    @Override
    public OrderCountData getOrderCountOfStatusByShopId(Long shopId) {
        return orderMapper.getOrderCountOfStatusByShopId(shopId);
    }

    @Override
    public List<User> listUserByConsAmount(BigDecimal minAmount, BigDecimal maxAmount, Date startDate, Date endTime) {
        return orderMapper.listUserByConsAmount(minAmount, maxAmount, startDate, endTime);
    }

    private Double getDouble(Double value) {
        if (Objects.isNull(value)) {
            return 0.0;
        }
        return value;
    }

    private Integer getInteger(Integer value) {
        if (Objects.isNull(value)) {
            return 0;
        }
        return value;
    }

    private Double divAverage(Integer a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    private Double divAverage(Double a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }
    private Double divAverage(Double a, Double b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }


}
